﻿#define _CRT_SECURE_NO_WARNINGS

#include"snack.h"

//设置坐标
void SetPos(int x, int y)
{
	HANDLE hand = GetStdHandle(STD_OUTPUT_HANDLE);
	COORD pos = { x,y };
	SetConsoleCursorPosition(hand, pos);
}


//加载欢迎界面 
void Welcome(void)
{
	SetPos(48, 15);
	HANDLE hand = GetStdHandle(STD_OUTPUT_HANDLE);
	wprintf(L"欢迎来到超级贪吃蛇");
	SetPos(50, 23);
	system("pause");
	system("cls");
	SetPos(37, 13);
	wprintf(L"用↑ ↓ ← →分别控制蛇的移动，F1加速，F2减速");
	SetPos(48, 18);
	wprintf(L"速度越快分数越高哦");
	SetPos(50, 23);
	system("pause");
	system("cls");
}


//加载地图
void CreatMap(void)
{
	int i = 0;
	//上
	for (i = 0; i < 40; i++)
	{
		wprintf(L"%lc", WALL);
	}

	//下
	SetPos(0, 30);
	for (i = 0; i < 40; i++)
	{
		wprintf(L"%lc", WALL);
	}
	
	//左
	for (i = 1; i < 30; i++)
	{
		SetPos(0, i);
		wprintf(L"%lc", WALL);
	}

	//右
	for (i = 1; i < 30; i++)
	{
		SetPos(78, i);
		wprintf(L"%lc", WALL);
	}
	SetPos(31, 32);
}

//添加蛇节点
pSnackNode BuySnackNode(int x, int y)
{
	pSnackNode newNode = (pSnackNode)malloc(sizeof(SnackNode));
	if (NULL == newNode)
	{
		perror("BuySnackNode fail");
		exit(1);
	}
	newNode->_x = x;
	newNode->_y = y;
	newNode->_next = NULL;
	return newNode;
}

//头插蛇节点
void PushFrontSnackNode(pSnackNode* pps, int x, int y)
{
	assert(pps);
	pSnackNode newNode = BuySnackNode(x, y);
	newNode->_next = *pps;
	*pps = newNode;

}

//尾插蛇节点
void PushBackSnackNode(pSnackNode* pps, int x, int y)
{
	assert(pps);
	pSnackNode newNode = BuySnackNode(x, y);
	//空链表
	if (NULL == *pps)
	{
		*pps = newNode;
	}
	//非空链表
	else
	{
		pSnackNode pcur = *pps;
		while (NULL != pcur->_next)
		{
			pcur = pcur->_next;
		}
		pcur->_next = newNode;
	}
}


//打印整条蛇
void PrintSnack(pSnack ps)
{
	assert(ps);
	pSnackNode pcur = ps->_snack;
	while (NULL != pcur)
	{
		SetPos(pcur->_x, pcur->_y);
		wprintf(L"%lc", BODY);
		pcur = pcur->_next;
	}
}

//初始化蛇
void InitSnack(pSnack ps)
{
	assert(ps);
	//初始化蛇节点
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		PushFrontSnackNode(&(ps->_snack), POS_X + 2 * i, POS_Y);
	}

	//初始化运动状态、运动方向、运动速度、食物分数、总分
	ps->_dir = RIGHT;
	ps->_status = OK;
	ps->_SleepTime = 200;
	ps->_foodWeight = 8;
	ps->_score = 0;

	//打印整个蛇
	PrintSnack(ps);

}

//设置食物位置
void SetFood(pSnack ps)
{
	assert(ps);
	int x = 0;
	int y = 0;
	bool flag = true;
	do
	{
		//随机设置食物，x为2的倍数
		do
		{
			x = rand() % 75 + 2;//2~76
			y = rand() % 29 + 1;//1~29
		} while (x % 2 != 0);
		
		//判断食物是否与蛇身重合
		flag = false;
		pSnackNode pcur = ps->_snack;
		while (NULL != pcur)
		{
			if (pcur->_x == x && pcur->_y == y)
			{
				flag = true;
				break;
			}
			pcur = pcur->_next;
		}

	} while (flag);

	//设置食物坐标并打印
	pSnackNode foodPos = BuySnackNode(x, y);
	ps->_foodPos = foodPos;
	SetPos(x, y);
	wprintf(L"%lc", FOOD);
}


//打印帮助信息
void PrintHelpInfo(pSnack ps)
{
	SetPos(85, 16);
	wprintf(L"不能撞墙，也不能撞到自己");
	SetPos(85, 17);
	wprintf(L"用↑ ↓ ← →分别控制蛇的移动");
	SetPos(85, 18);
	wprintf(L"F1——加速，F2——减速");
	SetPos(85, 19);
	wprintf(L"space——暂停，ESC——退出");
	SetPos(85, 20);
	wprintf(L"速度越快分数越高哦");
	SetPos(85, 30);
	wprintf(L"湖北工业大学_MoguSoup@版权");
}


//检测是否撞到墙
void KillByWall(pSnack ps)
{
	assert(ps);
	int x = ps->_snack->_x;
	int y = ps->_snack->_y;
	if ((x == 0) || (x == 78) || (y == 0) || (y == 30))
	{
		ps->_status = KILL_BY_WALL;
	}
}

//检测是否撞到自己
void KillBySelf(pSnack ps)
{
	assert(ps);
	int x = ps->_snack->_x;
	int y = ps->_snack->_y;
	pSnackNode pcur = ps->_snack->_next;
	while (NULL != pcur)
	{
		if ((pcur->_x == x) && (pcur->_y == y))
		{
			ps->_status = KILL_BY_SELF;
			break;
		}
		pcur = pcur->_next;
	}
}

//蛇移动一步
void SnackMove(pSnack ps)
{
	assert(ps && ps->_snack);
	pSnackNode pcur = BuySnackNode(ps->_snack->_x, ps->_snack->_y);
	//蛇头移动
	switch (ps->_dir)
	{
	case UP:
		pcur->_y -= 1;
		break;
	case DOWN:
		pcur->_y += 1;
		break;
	case LEFT:
		pcur->_x -= 2;
		break;
	case RIGHT:
		pcur->_x += 2;
		break;
	default:
		SetPos(POS_X, 31);
		printf("蛇迷路了");
		break;
	}
	//检测是否吃到食物
	int x = ps->_foodPos->_x;
	int y = ps->_foodPos->_y;
	if ((pcur->_x == x) && (pcur->_y == y))
	{
		//吃到食物
		pcur->_next = ps->_snack;
		ps->_snack = pcur;
		PrintSnack(ps);
		ps->_score += ps->_foodWeight;
		SetFood(ps);
	}
	else
	{
		//没吃到食物
		pcur->_next = ps->_snack;
		ps->_snack = pcur;
		while (NULL != pcur->_next->_next)
		{
			SetPos(pcur->_x, pcur->_y);
			wprintf(L"%lc", BODY);
			pcur = pcur->_next;
		}
		//末尾打印空格
		SetPos(pcur->_next->_x, pcur->_next->_y);
		printf("  ");
		free(pcur->_next);
		pcur->_next = NULL;
	}

	//检测是否撞到墙
	KillByWall(ps);
	//检测是否撞到自己
	KillBySelf(ps);
}


//暂停游戏
void Pause(void)
{
	do
	{
		Sleep(100);
	} while (0 == KEY_PRESS(VK_SPACE));
}


//开始游戏
void GameStart(pSnack ps)
{
	assert(ps);
	//设置控制台规格
	system("mode con cols=120 lines=35");
	system("title 超级贪吃蛇");
	//隐藏光标
	HANDLE hand = GetStdHandle(STD_OUTPUT_HANDLE);
	CONSOLE_CURSOR_INFO cursor;
	GetConsoleCursorInfo(hand, &cursor);
	cursor.bVisible = false;
	SetConsoleCursorInfo(hand, &cursor);
	//加载欢迎界面
	Welcome();
	//加载地图
	CreatMap();
	//初始化蛇
	InitSnack(ps);
	//设置食物位置
	SetFood(ps);
}

//按键控制蛇移动
void MotorSnack(pSnack ps)
{
	if (1 == KEY_PRESS(VK_UP) && DOWN != ps->_dir)//上
	{
		ps->_dir = UP;
	}
	else if (1 == KEY_PRESS(VK_DOWN) && UP != ps->_dir)//下
	{
		ps->_dir = DOWN;
	}
	else if (1 == KEY_PRESS(VK_LEFT) && RIGHT != ps->_dir)//左
	{
		ps->_dir = LEFT;
	}
	else if (1 == KEY_PRESS(VK_RIGHT) && LEFT != ps->_dir)//右
	{
		ps->_dir = RIGHT;
	}
	else if (1 == KEY_PRESS(VK_SPACE))//暂停游戏
	{
		Pause();
	}
	else if (1 == KEY_PRESS(VK_ESCAPE))//退出游戏
	{
		ps->_status = END_NORMAL;
	}
	else if (1 == KEY_PRESS(VK_F1))//加速
	{
		if (ps->_SleepTime > 50)
		{
			ps->_foodWeight += 2;
			ps->_SleepTime -= 50;
		}
	}
	else if (1 == KEY_PRESS(VK_F2))//减速
	{
		if (ps->_foodWeight > 2)
		{
			ps->_foodWeight -= 2;
			ps->_SleepTime += 50;
		}
	}
}


//运行游戏
void GameRun(pSnack ps)
{
	assert(ps);
	//打印帮助信息
	PrintHelpInfo(ps);
	do
	{

		SetPos(85, 5);
		printf("当前得分：%d", ps->_score);
		SetPos(85, 6);
		printf("当前速度：%d档", (400 - ps->_SleepTime) / 50);
		SetPos(85, 7);
		printf("每个食物分数：%2d", ps->_foodWeight);
		MotorSnack(ps);
		SnackMove(ps);
		Sleep(ps->_SleepTime);
	} while (OK == ps->_status);
}

//结束游戏
void GameOver(pSnack ps)
{
	assert(ps);
	SetPos(30, 15);
	if (KILL_BY_WALL == ps->_status)
	{
		wprintf(L"成就：不撞南墙不回头");
	}
	else if (KILL_BY_SELF == ps->_status)
	{
		wprintf(L"成就：自食其果");
	}
	else if (END_NORMAL == ps->_status)
	{
		wprintf(L"成功退出游戏");
	}
	//释放内存
	pSnackNode pcur = ps->_snack;
	while (NULL != pcur)
	{
		pSnackNode del = pcur;
		pcur = pcur->_next;
		free(del);
		del = NULL;
	}

}